// CSV 模块中文API封装
const fs = require('fs');
const path = require('path');

/**
 * 从CSV文件读取数据
 * @param {string} 文件路径 - CSV文件路径
 * @param {Object} 选项 - 读取选项，包括分隔符、编码等
 * @returns {Array} CSV数据数组
 */
function 读取CSV文件(文件路径, 选项 = {}) {
  if (!fs.existsSync(文件路径)) {
    throw new Error(`文件不存在: ${文件路径}`);
  }
  
  try {
    const 内容 = fs.readFileSync(文件路径, { 
      encoding: 选项.编码 || 'utf8' 
    });
    return 解析CSV(内容, 选项);
  } catch (错误) {
    throw new Error(`读取CSV文件失败: ${错误.message}`);
  }
}

/**
 * 将数据写入CSV文件
 * @param {string} 文件路径 - CSV文件路径
 * @param {Array} 数据 - 要写入的数据数组
 * @param {Object} 选项 - 写入选项，包括分隔符、编码等
 */
function 写入CSV文件(文件路径, 数据, 选项 = {}) {
  try {
    const csv内容 = 生成CSV(数据, 选项);
    fs.writeFileSync(文件路径, csv内容, { 
      encoding: 选项.编码 || 'utf8' 
    });
  } catch (错误) {
    throw new Error(`写入CSV文件失败: ${错误.message}`);
  }
}

/**
 * 解析CSV字符串
 * @param {string} csv字符串 - CSV格式的字符串
 * @param {Object} 选项 - 解析选项
 * @returns {Array} 解析后的数据数组
 */
function 解析CSV(csv字符串, 选项 = {}) {
  try {
    const 分隔符 = 选项.分隔符 || ',';
    const 引号 = 选项.引号 || '"';
    const 跳过标题行 = 选项.跳过标题行 || false;
    const 行 = csv字符串.split(/\r?\n/).filter(行 => 行.trim() !== '');
    const 结果 = [];
    
    for (let i = 0; i < 行.length; i++) {
      // 跳过标题行
      if (跳过标题行 && i === 0) continue;
      
      // 解析单行
      const 解析结果 = 解析CSV行(行[i], 分隔符, 引号);
      结果.push(解析结果);
    }
    
    return 结果;
  } catch (错误) {
    throw new Error(`解析CSV失败: ${错误.message}`);
  }
}

/**
 * 生成CSV字符串
 * @param {Array} 数据 - 要转换的数据数组
 * @param {Object} 选项 - 生成选项
 * @returns {string} CSV格式的字符串
 */
function 生成CSV(数据, 选项 = {}) {
  try {
    const 分隔符 = 选项.分隔符 || ',';
    const 引号 = 选项.引号 || '"';
    const 包含标题行 = 选项.包含标题行 !== false;
    const 标题行 = 选项.标题行 || [];
    
    let csv字符串 = '';
    
    // 添加标题行
    if (包含标题行 && 标题行.length > 0) {
      csv字符串 += 标题行.map(单元格 => 格式化CSV单元格(单元格, 分隔符, 引号)).join(分隔符) + '\n';
    }
    
    // 添加数据行
    for (const 行数据 of 数据) {
      if (Array.isArray(行数据)) {
        csv字符串 += 行数据.map(单元格 => 格式化CSV单元格(单元格, 分隔符, 引号)).join(分隔符) + '\n';
      } else if (typeof 行数据 === 'object') {
        // 如果是对象，先获取键作为标题（如果没有提供标题）
        if (包含标题行 && 标题行.length === 0) {
          const 对象键 = Object.keys(行数据);
          csv字符串 += 对象键.map(键 => 格式化CSV单元格(键, 分隔符, 引号)).join(分隔符) + '\n';
        }
        // 然后添加值
        const 对象值 = Object.values(行数据);
        csv字符串 += 对象值.map(值 => 格式化CSV单元格(值, 分隔符, 引号)).join(分隔符) + '\n';
      }
    }
    
    return csv字符串.trim();
  } catch (错误) {
    throw new Error(`生成CSV失败: ${错误.message}`);
  }
}

/**
 * 解析CSV单行
 * @param {string} 行字符串 - CSV行字符串
 * @param {string} 分隔符 - 分隔符字符
 * @param {string} 引号 - 引号字符
 * @returns {Array} 解析后的行数据数组
 */
function 解析CSV行(行字符串, 分隔符, 引号) {
  const 结果 = [];
  let 当前字段 = '';
  let 在引号内 = false;
  
  for (let i = 0; i < 行字符串.length; i++) {
    const 字符 = 行字符串[i];
    
    if (字符 === 引号) {
      // 检查是否是转义引号（两个连续的引号）
      if (i + 1 < 行字符串.length && 行字符串[i + 1] === 引号) {
        当前字段 += 引号;
        i++; // 跳过下一个引号
      } else {
        在引号内 = !在引号内;
      }
    } else if (字符 === 分隔符 && !在引号内) {
      结果.push(当前字段);
      当前字段 = '';
    } else {
      当前字段 += 字符;
    }
  }
  
  结果.push(当前字段);
  return 结果;
}

/**
 * 格式化CSV单元格
 * @param {*} 单元格值 - 单元格的值
 * @param {string} 分隔符 - 分隔符字符
 * @param {string} 引号 - 引号字符
 * @returns {string} 格式化后的单元格字符串
 */
function 格式化CSV单元格(单元格值, 分隔符, 引号) {
  // 处理null和undefined
  if (单元格值 === null || 单元格值 === undefined) {
    return '';
  }
  
  let 字符串值 = String(单元格值);
  
  // 检查是否需要引号
  if (字符串值.includes(分隔符) || 字符串值.includes(引号) || 
      字符串值.includes('\n') || 字符串值.includes('\r')) {
    // 转义内部引号
    字符串值 = 字符串值.split(引号).join(引号 + 引号);
    // 添加引号
    return 引号 + 字符串值 + 引号;
  }
  
  return 字符串值;
}

/**
 * 将JSON数据转换为CSV
 * @param {Array} json数据 - JSON对象数组
 * @param {Object} 选项 - 转换选项
 * @returns {string} CSV格式字符串
 */
function JSON转CSV(json数据, 选项 = {}) {
  try {
    if (!Array.isArray(json数据) || json数据.length === 0) {
      return '';
    }
    
    // 获取所有唯一的键作为标题
    const 所有键 = new Set();
    json数据.forEach(对象 => {
      if (typeof 对象 === 'object' && 对象 !== null) {
        Object.keys(对象).forEach(键 => 所有键.add(键));
      }
    });
    
    const 标题 = Array.from(所有键);
    
    // 准备数据行
    const 数据行 = json数据.map(对象 => {
      return 标题.map(键 => 对象[键] || '');
    });
    
    // 生成CSV
    return 生成CSV(数据行, { ...选项, 标题行: 标题, 包含标题行: true });
  } catch (错误) {
    throw new Error(`JSON转CSV失败: ${错误.message}`);
  }
}

/**
 * 将CSV转换为JSON
 * @param {string} csv字符串 - CSV格式字符串
 * @param {Object} 选项 - 转换选项
 * @returns {Array} JSON对象数组
 */
function CSV转JSON(csv字符串, 选项 = {}) {
  try {
    // 解析CSV
    const 数据 = 解析CSV(csv字符串, { ...选项, 跳过标题行: false });
    
    if (数据.length < 2) {
      return [];
    }
    
    // 第一行作为标题
    const 标题 = 数据[0];
    const json结果 = [];
    
    // 转换数据行
    for (let i = 1; i < 数据.length; i++) {
      const 对象 = {};
      标题.forEach((键, 索引) => {
        对象[键] = 数据[i][索引] || '';
      });
      json结果.push(对象);
    }
    
    return json结果;
  } catch (错误) {
    throw new Error(`CSV转JSON失败: ${错误.message}`);
  }
}

/**
 * 验证CSV格式
 * @param {string} csv字符串 - 要验证的CSV字符串
 * @returns {boolean} 是否是有效的CSV格式
 */
function 验证CSV格式(csv字符串) {
  try {
    // 尝试解析，如果不抛出错误则认为有效
    解析CSV(csv字符串);
    return true;
  } catch {
    return false;
  }
}

/**
 * 获取CSV文件信息
 * @param {string} 文件路径 - CSV文件路径
 * @returns {Object} 文件信息对象
 */
function 获取CSV文件信息(文件路径) {
  if (!fs.existsSync(文件路径)) {
    throw new Error(`文件不存在: ${文件路径}`);
  }
  
  try {
    const 数据 = 读取CSV文件(文件路径);
    const 统计信息 = fs.statSync(文件路径);
    
    return {
      行数: 数据.length,
      列数: 数据.length > 0 ? 数据[0].length : 0,
      文件大小: 统计信息.size,
      创建时间: 统计信息.birthtime,
      修改时间: 统计信息.mtime
    };
  } catch (错误) {
    throw new Error(`获取CSV文件信息失败: ${错误.message}`);
  }
}

/**
 * 合并多个CSV文件
 * @param {Array} 文件路径列表 - CSV文件路径数组
 * @param {string} 输出路径 - 输出文件路径
 * @param {Object} 选项 - 合并选项
 */
function 合并CSV文件(文件路径列表, 输出路径, 选项 = {}) {
  try {
    const 所有数据 = [];
    let 标题行 = null;
    
    文件路径列表.forEach((文件路径, 索引) => {
      const 数据 = 读取CSV文件(文件路径);
      
      if (索引 === 0) {
        // 第一个文件包含标题
        标题行 = 数据[0];
        所有数据.push(...数据);
      } else {
        // 后续文件跳过标题
        所有数据.push(...数据.slice(1));
      }
    });
    
    写入CSV文件(输出路径, 所有数据, 选项);
  } catch (错误) {
    throw new Error(`合并CSV文件失败: ${错误.message}`);
  }
}

/**
 * 过滤CSV数据
 * @param {Array} csv数据 - CSV数据数组
 * @param {Function} 过滤函数 - 过滤条件函数
 * @returns {Array} 过滤后的数据数组
 */
function 过滤CSV数据(csv数据, 过滤函数) {
  try {
    if (csv数据.length === 0) return [];
    
    // 保留标题行
    const 标题 = csv数据[0];
    const 数据行 = csv数据.slice(1);
    
    // 创建临时对象以便于过滤
    const 对象数组 = 数据行.map(行 => {
      const 对象 = {};
      标题.forEach((键, 索引) => {
        对象[键] = 行[索引] || '';
      });
      return 对象;
    });
    
    // 过滤
    const 过滤后的对象 = 对象数组.filter(过滤函数);
    
    // 转换回数组格式
    const 过滤后的行 = 过滤后的对象.map(对象 => {
      return 标题.map(键 => 对象[键] || '');
    });
    
    // 返回包含标题的结果
    return [标题, ...过滤后的行];
  } catch (错误) {
    throw new Error(`过滤CSV数据失败: ${错误.message}`);
  }
}

/**
 * 排序CSV数据
 * @param {Array} csv数据 - CSV数据数组
 * @param {number|string} 列索引或标题 - 用于排序的列
 * @param {boolean} 降序 - 是否降序排序
 * @returns {Array} 排序后的数据数组
 */
function 排序CSV数据(csv数据, 列索引或标题, 降序 = false) {
  try {
    if (csv数据.length <= 1) return csv数据;
    
    // 保留标题行
    const 标题 = csv数据[0];
    const 数据行 = csv数据.slice(1);
    
    // 确定排序列的索引
    let 排序索引 = 0;
    if (typeof 列索引或标题 === 'string') {
      排序索引 = 标题.indexOf(列索引或标题);
      if (排序索引 === -1) {
        throw new Error(`找不到列标题: ${列索引或标题}`);
      }
    } else {
      排序索引 = 列索引或标题;
    }
    
    // 排序
    数据行.sort((a, b) => {
      const 值A = a[排序索引] || '';
      const 值B = b[排序索引] || '';
      
      // 尝试数字排序
      const 数值A = parseFloat(值A);
      const 数值B = parseFloat(值B);
      
      if (!isNaN(数值A) && !isNaN(数值B)) {
        return 降序 ? 数值B - 数值A : 数值A - 数值B;
      }
      
      // 字符串排序
      if (值A < 值B) return 降序 ? 1 : -1;
      if (值A > 值B) return 降序 ? -1 : 1;
      return 0;
    });
    
    // 返回包含标题的结果
    return [标题, ...数据行];
  } catch (错误) {
    throw new Error(`排序CSV数据失败: ${错误.message}`);
  }
}

/**
 * 去重CSV数据
 * @param {Array} csv数据 - CSV数据数组
 * @param {Array} 比较列 - 用于比较重复的列索引数组
 * @returns {Array} 去重后的数据数组
 */
function 去重CSV数据(csv数据, 比较列 = []) {
  try {
    if (csv数据.length <= 1) return csv数据;
    
    // 保留标题行
    const 标题 = csv数据[0];
    const 数据行 = csv数据.slice(1);
    
    const 唯一键集合 = new Set();
    const 结果 = [标题];
    
    数据行.forEach(行 => {
      // 生成唯一键
      let 唯一键;
      if (比较列.length > 0) {
        唯一键 = 比较列.map(索引 => 行[索引] || '').join('|');
      } else {
        唯一键 = 行.join('|');
      }
      
      if (!唯一键集合.has(唯一键)) {
        唯一键集合.add(唯一键);
        结果.push(行);
      }
    });
    
    return 结果;
  } catch (错误) {
    throw new Error(`去重CSV数据失败: ${错误.message}`);
  }
}

/**
 * 导出CSV模块
 */
module.exports = {
  // 核心功能
  读取CSV文件,
  写入CSV文件,
  解析CSV,
  生成CSV,
  
  // 转换功能
  JSON转CSV,
  CSV转JSON,
  
  // 文件操作
  获取CSV文件信息,
  合并CSV文件,
  
  // 数据处理
  过滤CSV数据,
  排序CSV数据,
  去重CSV数据,
  验证CSV格式,
  
  // 常量
  分隔符: {
    逗号: ',',
    分号: ';',
    制表符: '\t',
    竖线: '|'
  }
};